<?php declare(strict_types=1);

/**
 * @author      guosir
 * @copyright   2023-2025 owner
 **/

namespace Srv\Apps\Apis\Log\Ctl;

use Srv\Apps\Apis\Admin\Ctl\AdminCtl;
use Srv\Apps\Apis\Common\IdxCtl\IdxIp;
use Srv\Apps\Proto\DTO\Log\LogListDTO;
use Srv\Apps\Proto\Enum\Log\LogResultEnum;
use Srv\Apps\Proto\VO\Log\LogListVO;
use Srv\Apps\Proto\VO\Log\LogVO;
use Srv\Libs\Common\CommArray;
use Srv\Libs\Common\CommJson;
use Srv\Libs\Common\CommTime;
use Srv\Libs\Frame\AuthData;
use Srv\Libs\Frame\ControllerAbstract;
use Srv\Libs\Frame\Page;
use Srv\Libs\Storage\DataMysql;
use Srv\Libs\Tools\IpAddr;

final class LogCtl extends ControllerAbstract
{
    private ?DataMysql $DbAuto              = null;     // DB-Write
    public const SIGN_IN_ACCOUNT_PASS       = 'signInAccountPass';          // 帐号登入
    public const SIGN_IN_ACCOUNT_CODE       = 'getSignInCode';              // 获取帐号登入验证码
    public const AUTH_REQUEST_ASYNC         = 'reqInfoListAsync';           // 权限同步
    public const AUTH_ROLE_ADD              = 'authRoleAdd';                // 角色新增
    public const AUTH_ROLE_EDIT             = 'authRoleEdit';               // 角色编辑
    public const ADMIN_USER_ADD             = 'admUserAdd';                 // 管理员新增
    public const ADMIN_USER_EDIT            = 'admUserEdit';                // 管理员编辑
    public const ADMIN_AUTH_EDIT            = 'admUserAuthEdit';            // 管理员权限编辑
    public const ADMIN_ME_PASS_EDIT         = 'admMePassEdit';              // 当前管理员修改密码
    public const STORAGE_STS_GET            = 'getStorageSTS';              // 获取云存储STS
    public const STORAGE_GS_GET             = 'getStorageGS';               // 获取云存储GS
    public const AD_OPEN_ADD                = 'adOpenAdd';                  // 开屏广告新增
    public const AD_OPEN_EDIT               = 'adOpenEdit';                 // 开屏广告编辑
    public const APP_VERSION_ADD            = 'appVersionAdd';              // App版本新增
    public const APP_VERSION_EDIT           = 'appVersionEdit';             // App版本编辑
    public const GLOBAL_CONF_ADD            = 'globalConfAdd';              // 全局配置新增
    public const GLOBAL_CONF_EDIT           = 'globalConfEdit';             // 全局配置编辑
    public const GLOBAL_APP_CONF_EDIT       = 'setAppGlobalConf';           // 全局配置编辑
    public const PAY_GOODS_ADD              = 'payGoodsAdd';                // 支付产品新增
    public const PAY_GOODS_EDIT             = 'payGoodsEdit';               // 支付产品编辑
    public const PAY_TPL_ADD                = 'payTplAdd';                  // 支付产品新增
    public const PAY_TPL_EDIT               = 'payTplEdit';                 // 支付产品编辑
    public const SKIT_CATEGORY_ADD          = 'skitCategoryAdd';            // 短剧类别新增
    public const SKIT_CATEGORY_EDIT         = 'skitCategoryEdit';           // 短剧类别编辑
    public const SKIT_CHASING_ADD           = 'skitCategoryAdd';            // 追剧记录默认配置新增
    public const SKIT_CHASING_EDIT          = 'skitCategoryEdit';           // 追剧记录默认配置编辑
    public const SKIT_CHASING_DEL           = 'skitCategoryDel';            // 追剧记录默认配置删除
    public const SKIT_INFO_ADD              = 'skitInfoAdd';                // 短剧信息新增
    public const SKIT_INFO_EDIT             = 'skitInfoEdit';               // 短剧信息编辑
    public const SKIT_LABEL_ADD             = 'skitLabelAdd';               // 短剧标签新增
    public const SKIT_LABEL_EDIT            = 'skitLabelEdit';              // 短剧标签编辑
    public const SKIT_SERIES_ADD            = 'skitSeriesAdd';              // 短剧剧集新增
    public const SKIT_SERIES_EDIT           = 'skitSeriesEdit';             // 短剧剧集编辑
    public const SKIT_SERIES_ADD_BATCH      = 'skitSeriesAddBatch';         // 短剧剧集新增-批量
    public const SKIT_THEATER_ADD           = 'skitTheaterAdd';             // 剧场信息新增
    public const SKIT_THEATER_EDIT          = 'skitTheaterEdit';            // 剧场信息编辑
    public const SKIT_THEATER_DEL           = 'skitTheaterDel';             // 剧场信息删除
    public const SKIT_THEATER_WEB_ADD       = 'skitTheaterWebAdd';          // 剧场Web信息新增
    public const SKIT_THEATER_WEB_EDIT      = 'skitTheaterWebEdit';         // 剧场Web信息编辑
    public const SKIT_THEATER_WEB_DEL       = 'skitTheaterWebDel';          // 剧场Web信息删除
    public const SKIT_TPL_RMD_ADD           = 'skitTplRmdAdd';              // 推荐短剧模板新增
    public const SKIT_TPL_RMD_EDIT          = 'skitTplRmdEdit';             // 推荐短剧模板编辑
    public const SKIT_TPL_RMD_DEL           = 'skitTplRmdDel';              // 推荐短剧模板删除
    public const USER_EDIT                  = 'userEdit';                   // 用户信息编辑
    public const BANNER_ADD                 = 'bannerAdd';                  // Banner新增
    public const BANNER_EDIT                = 'bannerEdit';                 // Banner编辑
    public const BANNER_WEB_ADD             = 'bannerWebAdd';               // BannerWeb新增
    public const BANNER_WEB_EDIT            = 'bannerWebEdit';              // BannerWeb编辑
    public const PUT_LINK_ADD               = 'putLinkAdd';                 // 投放链接新增
    public const PUT_LINK_EDIT              = 'putLinkEdit';                // 投放链接编辑
    public const TASK_EDIT                  = 'taskEdit';                   // 任务编辑
    public const LOTTERY_ITEM_ADD           = 'lotteryItemAdd';             // 转盘奖项新增
    public const LOTTERY_ITEM_EDIT          = 'lotteryItemEdit';            // 转盘奖项编辑
    public const TASK_TPL_ADD               = 'taskTplAdd';                 // 任务模板新增
    public const TASK_TPL_EDIT              = 'taskTplEdit';                // 任务模板编辑
    public const CONTENT_ADD                = 'contentAdd';                 // 内容新增
    public const CONTENT_EDIT               = 'contentEdit';                // 内容编辑
    public const AD_REWARD_CONF_ADD         = 'adRewardConfAdd';            // 广告奖励配置新增
    public const AD_REWARD_CONF_EDIT        = 'adRewardConfEdit';           // 广告奖励配置编辑
    public const LOGOUT_REVIEW_SET          = 'setLogoutReview';            // 注销审核
    public const SKIT_INFO_EXT_EDIT         = 'skitInfoExtEdit';            // 短剧扩展数据编辑
    public const SKIT_SERIES_EXT_EDIT       = 'skitSeriesExtEdit';          // 剧集扩展数据编辑
    public const COIN_GIVE_INVALID          = 'invalidCoinGive';            // 看点赠送设置失效
    public const COIN_GIVE_RECHARGE         = 'rechargeCoinGive';           // 充值看点赠送
    public const WALLET_COIN_RECHARGE       = 'walletBalanceRechargeCoin';  // 充值Coin
    public const BAD_WORD_ADD               = 'badWordAdd';                 // 敏感词新增
    public const BAD_WORD_EDIT              = 'badWordEdit';                // 敏感词编辑
    public const FEEDBACK_REVIEW_SET        = 'setFeedbackReview';          // 注销审核
    public const RECHARGE_ACT_ADD           = 'rechargeActAdd';             // 充值活动新增
    public const RECHARGE_ACT_EDIT          = 'rechargeActEdit';            // 充值活动编辑
    public const STAT_SQL_EXEC              = 'getStatDataList';            // 统计数据结果
    public const STAT_DELIVER_ADD           = 'statDeliverAdd';             // 每日投放新增
    public const STAT_DELIVER_EDIT          = 'statDeliverEdit';            // 每日投放编辑
    public const WAPP_LINK_ADD              = 'wappLinkAdd';                // Web2App链接新增
    public const WAPP_LINK_EDIT             = 'wappLinkEdit';               // Web2App链接编辑

    /**
     * @return static
     * tag
     */
    final public static function tag():self
    {
        $thisObject                         = self::tagGet();
        if($thisObject instanceof self){
            $thisObject->DbAuto             = self::getDbAuto();
        }
        return $thisObject;
    }

    /**
     * @param Page $Page
     * @param array $whereData
     * @return LogListVO|null
     * getLogList
     */
    public function getLogList(Page $Page, array $whereData): ?LogListVO
    {
        $limitString        = $Page->getLimitString();
        $whereString        = ' WHERE 1 ';
        // 检索条件
        if(count($whereData) > 0)foreach ($whereData as $key => $val){
            switch ($key){
                case LogListDTO::_admUserId:
                    $whereString    .= (strlen($whereString)>0?' AND ':'').'auir_id='. intval($val);
                    break;
                case LogListDTO::_nonce:
                    $whereString    .= (strlen($whereString)>0?' AND ':'').'utnr_nonce='. intval($val);
                    break;
                case LogListDTO::_key:
                    $whereString    .= (strlen($whereString)>0?' AND ':'').'algr_key LIKE \'%'.$this->DbAuto->getRealEscapeString($val).'%\'';
                    break;
                case LogListDTO::_result:
                    $whereString    .= (strlen($whereString)>0?' AND ':'').'algr_result='. intval($val);
                    break;
                case LogListDTO::_createTimeStart:
                    $whereString    .= (strlen($whereString)>0?' AND ':'').'algr_create_time>='. intval($val);
                    break;
                case LogListDTO::_createTimeStop:
                    $whereString    .= (strlen($whereString)>0?' AND ':'').'algr_create_time<='. intval($val);
                    break;
            }
        }
        $isFail             = false;
        $sql                = 'SELECT SQL_CALC_FOUND_ROWS algr_id, auir_id, utnr_nonce, algr_key, algr_result, algr_data, algr_text, algr_ip, algr_create_time FROM '.$this->DbAuto->getTableNameAll('adm_log_record').$whereString.' ORDER BY algr_id DESC '.$limitString;
        $logRecordList      = $this->DbAuto->getData($sql, $isFail);
        $totalNum           = $this->DbAuto->getDataInt('SELECT FOUND_ROWS() as num', 'num');
        if($isFail) return null;
        $LogVOList          = [];
        if(CommArray::isForeach($logRecordList)){
            $auirIdList         = array_map('intval', array_unique(array_filter(array_column($logRecordList, 'auir_id'))));
            $admUserInfoSrcList = AdminCtl::tag()->getAdmUserInfoSrcBatch($auirIdList);
            foreach($logRecordList as $logRecord){
                $algrIdItem     = intval($logRecord['algr_id']);
                if($algrIdItem < 1) continue;
                $LogVO          = $this->getLogVO($logRecord);
                if(!($LogVO instanceof LogVO)) continue;
                $LogVO->setAdmUserName($admUserInfoSrcList[intval($logRecord['auir_id'])]['auir_name']??'');
                $LogVOList[]    = $LogVO;
            }
        }
        $LogListVO           = new LogListVO();
        $LogListVO->setList($LogVOList);
        $LogListVO->setPage($Page->getPageVO($totalNum));
        return $LogListVO;
    }

    /**
     * @param array $logRecord
     * @return LogVO|null
     * getLogVO
     */
    public function getLogVO(array $logRecord): ?LogVO
    {
        $algrId     = intval($logRecord['algr_id']??0);
        if($algrId < 1) return null;
        $LogVO      = new LogVO();
        $LogVO->setAlgrId($algrId);
        $LogVO->setAdmUserId(intval($logRecord['auir_id']));
        $LogVO->setAdmUserName($admUserSrc['auir_name']??'');
        $LogVO->setNonce(intval($logRecord['utnr_nonce']));
        $LogVO->setKey(trim($logRecord['algr_key']));
        $LogVO->setResult(LogResultEnum::parseValue($logRecord['algr_result']));
        $LogVO->setData(trim($logRecord['algr_data']));
        $LogVO->setText(trim($logRecord['algr_text']));
        $IpString   = IdxIp::tag()->getIpStrByIntStr($logRecord['algr_ip']);
        $ipArea     = IpAddr::getLocationInfo($IpString);
        $LogVO->setIpString($IpString.'('.($ipArea['country']??'').')');
        $LogVO->setCreateTime(intval($logRecord['algr_create_time']));
        return $LogVO;
    }

    /**
     * @param string $key
     * @param int $result
     * @param string $text
     * @param array $data
     * @return int
     * logAdd
     */
    public function logAdd(string $key, int $result, string $text, array $data=[]):int
    {
        if(strlen($key) < 1 || !in_array($result, [0, 1, 2], true)) return 0;
        $currTime   = CommTime::getTimeStamp();
        $admUserId  = AuthData::getLoginUserId();
        $admUserId  = $admUserId < 1 ? 0 : $admUserId;
        $nonce      = AuthData::getLoginTokenNonce();
        $currIpStr  = IdxIp::tag()->getReqIpNumStr();
        $dataJson   = CommJson::encodeArray($data);
        $isFail     = false;
        $sql        = 'INSERT INTO '.$this->DbAuto->getTableNameAll('adm_log_record').' SET algr_key=\''.$this->DbAuto->getRealEscapeString($key) .'\', algr_result='.$result.', algr_data=\''.$this->DbAuto->getRealEscapeString($dataJson) .'\', algr_text=\''.$this->DbAuto->getRealEscapeString($text) .'\', algr_ip='.$currIpStr.', auir_id='.$admUserId.', utnr_nonce='.$nonce.', algr_create_time='.$currTime;
        $algrId     = $this->DbAuto->getDataId($sql, $isFail);
        if($isFail || $algrId < 1) return 0;
        return $algrId;
    }
}